#include <spine/Debug.h>
#include <spine/spine.h>
#include <stdio.h>

#ifdef MSVC
#pragma warning(disable : 4710)
#endif

using namespace spine;

void loadBinary(const String &binaryFile, const String &atlasFile, Atlas *&atlas, SkeletonData *&skeletonData,
				AnimationStateData *&stateData, Skeleton *&skeleton, AnimationState *&state) {
	atlas = new (__FILE__, __LINE__) Atlas(atlasFile, NULL);
	assert(atlas != NULL);

	SkeletonBinary binary(atlas);
	skeletonData = binary.readSkeletonDataFile(binaryFile);
	assert(skeletonData);

	skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
	assert(skeleton != NULL);

	stateData = new (__FILE__, __LINE__) AnimationStateData(skeletonData);
	assert(stateData != NULL);
	stateData->setDefaultMix(0.4f);

	state = new (__FILE__, __LINE__) AnimationState(stateData);
}

void loadJson(const String &jsonFile, const String &atlasFile, Atlas *&atlas, SkeletonData *&skeletonData,
			  AnimationStateData *&stateData, Skeleton *&skeleton, AnimationState *&state) {
	atlas = new (__FILE__, __LINE__) Atlas(atlasFile, NULL);
	assert(atlas != NULL);

	SkeletonJson json(atlas);
	skeletonData = json.readSkeletonDataFile(jsonFile);
	assert(skeletonData);

	skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
	assert(skeleton != NULL);

	stateData = new (__FILE__, __LINE__) AnimationStateData(skeletonData);
	assert(stateData != NULL);
	stateData->setDefaultMix(0.4f);

	state = new (__FILE__, __LINE__) AnimationState(stateData);
}

void dispose(Atlas *atlas, SkeletonData *skeletonData, AnimationStateData *stateData, Skeleton *skeleton,
			 AnimationState *state) {
	delete skeleton;
	delete state;
	delete stateData;
	delete skeletonData;
	delete atlas;
}

struct TestData {
	TestData(const String &jsonSkeleton, const String &binarySkeleton, const String &atlas) : _jsonSkeleton(
																									  jsonSkeleton),
																							  _binarySkeleton(
																									  binarySkeleton),
																							  _atlas(atlas) {}

	String _jsonSkeleton;
	String _binarySkeleton;
	String _atlas;
};

void testLoading() {
	Vector<TestData> testData;
	testData.add(TestData("examples/coin/export/coin-pro.json", "examples/coin/export/coin-pro.skel", "examples/coin/export/coin.atlas"));
	testData.add(TestData("examples/goblins/export/goblins-pro.json", "examples/goblins/export/goblins-pro.skel",
						  "examples/goblins/export/goblins.atlas"));
	testData.add(TestData("examples/raptor/export/raptor-pro.json", "examples/raptor/export/raptor-pro.skel",
						  "examples/raptor/export/raptor.atlas"));
	testData.add(TestData("examples/spineboy/export/spineboy-pro.json", "examples/spineboy/export/spineboy-pro.skel",
						  "examples/spineboy/export/spineboy.atlas"));
	testData.add(TestData("examples/stretchyman/export/stretchyman-pro.json", "examples/stretchyman/export/stretchyman-pro.skel",
						  "examples/stretchyman/export/stretchyman.atlas"));
	testData.add(TestData("examples/tank/export/tank-pro.json", "examples/tank/export/tank-pro.skel", "examples/tank/export/tank.atlas"));

	for (size_t i = 0; i < testData.size(); i++) {
		TestData &data = testData[i];
		Atlas *atlas = NULL;
		SkeletonData *skeletonData = NULL;
		AnimationStateData *stateData = NULL;
		Skeleton *skeleton = NULL;
		AnimationState *state = NULL;

		printf("Loading %s\n", data._jsonSkeleton.buffer());
		loadJson(data._jsonSkeleton, data._atlas, atlas, skeletonData, stateData, skeleton, state);
		dispose(atlas, skeletonData, stateData, skeleton, state);

		printf("Loading %s\n", data._binarySkeleton.buffer());
		loadBinary(data._binarySkeleton, data._atlas, atlas, skeletonData, stateData, skeleton, state);
		dispose(atlas, skeletonData, stateData, skeleton, state);
	}
}

namespace spine {
	SpineExtension *getDefaultExtension() {
		return new DefaultSpineExtension();
	}
}// namespace spine

int main(int argc, char **argv) {
	SP_UNUSED(argc);
	SP_UNUSED(argv);
	DebugExtension debug(SpineExtension::getInstance());
	SpineExtension::setInstance(&debug);

	testLoading();

	debug.reportLeaks();
}
